/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package neuralmusic;

import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.Random;

import javax.sound.midi.Receiver;
import javax.sound.midi.ShortMessage;
import javax.swing.JFrame;
import javax.swing.Timer;

import uk.co.drpj.util.tweaks.TweakableDouble;

import neuralmusic.brain.Global;
import neuralmusic.brain.IOBrainBuilder;
import neuralmusic.brain.RTScheduler;
import neuralmusic.brain.Util;

import neuralmusic.brain.ga.GABrainFactory;
import neuralmusic.brain.ga.Gene;
import neuralmusic.brain.gui.NetworkDisplayPanel;
import neuralmusic.brain.gui.NetworkMonitorPanel;
import neuralmusic.brain.module.Brain;
import neuralmusic.brain.module.Connection;
import neuralmusic.brain.module.Module;
import neuralmusic.brain.module.NeuronParams;
import neuralmusic.brain.module.RandomExcitor;
import neuralmusic.brain.module.Scheduler;
import neuralmusic.midiIO.MidiInConnector;
import neuralmusic.midiIO.NoteAction;
import neuralmusic.simplemidiplayer.MyMidiSystem;

/**
 * 
 * 
 * 
 * @author pjl
 */
public class MainMidiKeys {

	private static NetworkDisplayPanel brainPanel;
	private static NetworkMonitorPanel monPanel;
	private static MyMidiSystem midiSys;

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {

		midiSys = new MyMidiSystem();
		midiSys.openMidi();

		// -----BRAIN DRAIN ---------------------------------------------------

		int nInputs = 49;
		int nOut = 24;
		int nInternal = 100;
		int nInternalConnect = 20;
		int nInToGrey = 10;
		int nGreyToOut=20;
		
		NeuronParams pramIn = new NeuronParams();
		pramIn.thresh = 0.5f;
		pramIn.delayInSecs = 1e-3f; // don't delay inputs
		pramIn.outputVal = 1.0f;
		pramIn.timeConstant = (float) Util.halfLifeToTimeConstant(.4);

		Float inputConnectWeight = 1.0f;
		
		NeuronParams pramGrey = new NeuronParams();

		
		pramGrey.outputVal=2.0f;


		pramGrey.delayInSecs = .05f; // will be set by delayMin and Delaymax but it used for the timeConstant
		pramGrey.timeConstant = (float) (Util
				.halfLifeToTimeConstant(2 * pramGrey.delayInSecs));
		
		pramGrey.thresh = .7f;
		float delayMax=.1f;
		float delayMin=.02f;
		
		NeuronParams pramOut = new NeuronParams();
		
		
		pramOut.thresh = .1f;
		pramOut.delayInSecs = 1e-3f; // don't delay outputs		
		pramOut.outputVal = 1.0f;
		pramOut.timeConstant = (float) Util.halfLifeToTimeConstant(2.3);

		Float weightInToGrey = 10.0f;
		Float internalConnectWeight = 4.0f/nInternalConnect;
		Float weightGrayToOut = 1.0f;
		
		Rectangle rect = new Rectangle(0, 0, 400, 200);
		Random rand=new Random();
		
		
		Brain brain2 = IOBrainBuilder.buildIOBrain(nInputs, nOut, nInternal,
				nInternalConnect, nInToGrey, nGreyToOut, pramIn, pramGrey, pramOut,
				inputConnectWeight,weightInToGrey, internalConnectWeight,
				weightGrayToOut,delayMax,delayMin,rect,rand);

		
		
		
	//	Gene gene=GABrainFactory.encode(brain2);
		
	//	final Brain brain=GABrainFactory.decode(gene);
		
		
		
		final Brain brain=brain2;
		final Scheduler sched=new RTScheduler();
		brain.setScheduler(sched);
		
		
		
		//final Brain brain=brain1;
		
		Global.brain=brain;
		
		TweakableDouble randAmount=new TweakableDouble(0, 1.0, 0.0, .01, "Noise");
		
		Module gray; 
		
		
		gray=brain.getModuleByName("Grey");
		
		int nMax=gray.getNeurons().size()/20;
		final RandomExcitor noiseSource=new RandomExcitor(gray,nMax,rand,randAmount);
		brain.tweaks.add(randAmount);
		
		
		
		List<Connection> outputs = brain.getOutputs();

		assert(outputs.size() == nOut);

		 int chan = 1;
         ShortMessage shm = new ShortMessage();
         Receiver recv=midiSys.thru;

           shm.setMessage(ShortMessage.PROGRAM_CHANGE, chan,
                   12, 0);
           recv.send(shm, -1);
           
           
		for (int i = 0; i < nOut; i++) {
			NoteAction noteAction = new NoteAction(midiSys.thru, i + 60, chan,sched);
			outputs.get(i).setSink(noteAction);
		}

		MidiInConnector midiInToBrain = new MidiInConnector(midiSys.thru,
				brain.getInputs());

		midiSys.trans.setReceiver(midiInToBrain.getReceiver());

		new Thread() {
			@Override
			public void run() {
				brain.run(sched);
				
			}
		}.start();
		
		noiseSource.start();
		
		// --------------------------------------------

		JFrame frame = new JFrame();
		brainPanel = new NetworkDisplayPanel(brain);

		frame.setContentPane(brainPanel);

		frame.setVisible(true);

		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setBounds(0, 50, 800, 600);

		monPanel = new NetworkMonitorPanel(brain);
		JFrame monitorFrame = new JFrame();
		monitorFrame.setContentPane(monPanel);

		monitorFrame.pack();
		monitorFrame.setVisible(true);
		monitorFrame.setLocation(0, 700);

		Timer t = new Timer(100, new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				brainPanel.repaint();
				monPanel.myUpdate();
			}
		});
		
		t.start();
	
	}

}
